# simulator/sim_controller.py
"""
仿真控制器 - 基于MCP SDK
Simulation Controller with MCP SDK

使用FastMCP提供标准化的工具接口
"""

import os
import datetime
import json
import asyncio
from typing import Dict, List, Any, Optional
from mcp.server import FastMCP
from simulator.sim_engine import SimEngine, Target, WeatherCondition


class SimController:
    """仿真控制器 - 基于MCP SDK"""

    def __init__(self, log_file: str = "data/logs/sim_controller.log"):
        self.sim_engine = SimEngine()
        self.log_file = log_file
        self.sim_process = None  # 仿真进程引用（由GUI设置）
        self.on_simulation_started = None  # 仿真启动回调（由GUI设置）
        self.on_simulation_stopped = None  # 仿真停止回调（由GUI设置）
        self._init_log_file()

        # 创建MCP服务器
        self.mcp = FastMCP("radar-simulation")
        self._register_mcp_tools()

    def _init_log_file(self):
        """初始化日志文件"""
        header = "时间, 方法名, 参数, 结果, 状态\n"
        try:
            os.makedirs(os.path.dirname(self.log_file), exist_ok=True)
            if not os.path.exists(self.log_file) or os.path.getsize(self.log_file) == 0:
                with open(self.log_file, 'w', encoding='utf-8') as f:
                    f.write(header)
        except Exception as e:
            print(f"日志文件初始化失败: {e}")

    def _log_operation(self, method: str, params: Dict, result: Any, status: str):
        """记录操作日志"""
        try:
            current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            params_str = json.dumps(params, ensure_ascii=False)[:100]
            result_str = str(result)[:100]
            log_entry = f"{current_time}, {method}, {params_str}, {result_str}, {status}\n"

            with open(self.log_file, 'a', encoding='utf-8') as f:
                f.write(log_entry)
        except Exception as e:
            print(f"日志记录失败: {e}")

    def _register_mcp_tools(self):
        """注册MCP工具"""

        @self.mcp.tool()
        def get_status() -> Dict:
            """获取雷达仿真系统状态

            Returns:
                Dict: 包含仿真时间、目标信息、雷达参数、天气条件等的状态字典
            """
            try:
                status = self.sim_engine.get_simulation_status()

                result = {
                    "simulation_time": status['simulation_time'],
                    "targets": {
                        "total": status['total_targets'],
                        "detected": status['detected_targets'],
                        "detection_rate": status['detection_rate']
                    },
                    "detections": {
                        "total_count": status['total_detections']
                    },
                    "radar": {
                        "frequency_ghz": status['radar_params']['frequency'],
                        "power_w": status['radar_params']['power'],
                        "antenna_gain_db": status['radar_params']['antenna_gain'],
                        "detection_range_km": status['radar_params']['detection_range']
                    },
                    "weather": {
                        "temperature_c": status['weather_conditions']['temperature'],
                        "humidity_percent": status['weather_conditions']['humidity'],
                        "precipitation_mmh": status['weather_conditions']['precipitation'],
                        "wind_speed_kmh": status['weather_conditions']['wind_speed']
                    },
                    "is_running": status['is_running'],
                    "timestamp": datetime.datetime.now().isoformat()
                }

                self._log_operation("get_status", {}, result, "SUCCESS")
                return result

            except Exception as e:
                self._log_operation("get_status", {}, str(e), "ERROR")
                raise

        @self.mcp.tool()
        def add_target(target_id: str, position: List[float], velocity: List[float], rcs: float = 1.0) -> Dict:
            """添加雷达目标

            Args:
                target_id: 目标ID
                position: 位置坐标 [x, y, z] (米)
                velocity: 速度向量 [vx, vy, vz] (米/秒)
                rcs: 雷达截面积 (平方米), 默认1.0

            Returns:
                Dict: 添加结果信息
            """
            try:
                if len(position) != 3 or len(velocity) != 3:
                    raise ValueError("Position and velocity must have 3 components [x,y,z]")

                target = Target(target_id, tuple(position), tuple(velocity), rcs)
                self.sim_engine.add_target(target)

                result = {
                    "target_id": target_id,
                    "position": position,
                    "velocity": velocity,
                    "rcs": rcs,
                    "message": f"Target {target_id} added successfully"
                }

                self._log_operation("add_target", {"target_id": target_id}, result, "SUCCESS")
                return result

            except Exception as e:
                self._log_operation("add_target", {"target_id": target_id}, str(e), "ERROR")
                raise

        @self.mcp.tool()
        def remove_target(target_id: str) -> Dict:
            """移除雷达目标

            Args:
                target_id: 目标ID

            Returns:
                Dict: 移除结果信息
            """
            try:
                if target_id not in self.sim_engine.targets:
                    raise ValueError(f"Target '{target_id}' does not exist")

                self.sim_engine.remove_target(target_id)

                result = {
                    "target_id": target_id,
                    "message": f"Target {target_id} removed successfully"
                }

                self._log_operation("remove_target", {"target_id": target_id}, result, "SUCCESS")
                return result

            except Exception as e:
                self._log_operation("remove_target", {"target_id": target_id}, str(e), "ERROR")
                raise

        @self.mcp.tool()
        def set_radar_param(param_name: str, value: float) -> Dict:
            """设置雷达参数

            Args:
                param_name: 参数名称 (frequency/power/antenna_gain/detection_range)
                value: 参数值

            Returns:
                Dict: 参数设置结果
            """
            try:
                if param_name not in self.sim_engine.params:
                    available = list(self.sim_engine.params.keys())
                    raise ValueError(
                        f"Invalid parameter name: {param_name}. "
                        f"Available parameters: {', '.join(available)}"
                    )

                old_value = self.sim_engine.params[param_name]
                self.sim_engine.params[param_name] = value

                result = {
                    "param_name": param_name,
                    "old_value": old_value,
                    "new_value": value,
                    "message": f"Parameter {param_name} updated successfully"
                }

                self._log_operation("set_radar_param", {"param_name": param_name, "value": value}, result, "SUCCESS")
                return result

            except Exception as e:
                self._log_operation("set_radar_param", {"param_name": param_name}, str(e), "ERROR")
                raise

        @self.mcp.tool()
        def set_weather(temperature: float, humidity: float, precipitation: float, wind_speed: float) -> Dict:
            """设置天气条件

            Args:
                temperature: 温度 (摄氏度)
                humidity: 湿度 (百分比)
                precipitation: 降水量 (毫米/小时)
                wind_speed: 风速 (千米/小时)

            Returns:
                Dict: 天气设置结果
            """
            try:
                weather_params = {
                    'temperature': temperature,
                    'humidity': humidity,
                    'precipitation': precipitation,
                    'wind_speed': wind_speed
                }

                self.sim_engine.update_weather(weather_params)

                result = {
                    "weather": weather_params,
                    "message": "Weather conditions updated successfully"
                }

                self._log_operation("set_weather", weather_params, result, "SUCCESS")
                return result

            except Exception as e:
                self._log_operation("set_weather", locals(), str(e), "ERROR")
                raise

        @self.mcp.tool()
        def start_simulation() -> Dict:
            """开始雷达仿真

            Returns:
                Dict: 仿真启动结果
            """
            try:
                # 如果设置了仿真进程，则启动进程
                if self.sim_process is not None:
                    self.sim_process.start()
                    result = {
                        "is_running": True,
                        "message": "Simulation process started successfully"
                    }
                else:
                    # 如果没有仿真进程，只设置标志
                    self.sim_engine.is_running = True
                    result = {
                        "is_running": True,
                        "message": "Simulation started (engine mode)"
                    }

                # 无论哪种模式，都调用GUI回调
                if self.on_simulation_started is not None:
                    try:
                        self.on_simulation_started()
                    except Exception as e:
                        print(f"[SimController] 仿真启动回调错误: {e}")

                self._log_operation("start_simulation", {}, result, "SUCCESS")
                return result

            except Exception as e:
                self._log_operation("start_simulation", {}, str(e), "ERROR")
                raise

        @self.mcp.tool()
        def stop_simulation() -> Dict:
            """停止雷达仿真

            Returns:
                Dict: 仿真停止结果
            """
            try:
                # 如果设置了仿真进程，则停止进程
                if self.sim_process is not None:
                    self.sim_process.stop()
                    result = {
                        "is_running": False,
                        "message": "Simulation process stopped successfully"
                    }
                else:
                    # 如果没有仿真进程，只设置标志
                    self.sim_engine.is_running = False
                    result = {
                        "is_running": False,
                        "message": "Simulation stopped (engine mode)"
                    }

                # 无论哪种模式，都调用GUI回调
                if self.on_simulation_stopped is not None:
                    try:
                        self.on_simulation_stopped()
                    except Exception as e:
                        print(f"[SimController] 仿真停止回调错误: {e}")

                self._log_operation("stop_simulation", {}, result, "SUCCESS")
                return result

            except Exception as e:
                self._log_operation("stop_simulation", {}, str(e), "ERROR")
                raise

        @self.mcp.tool()
        def reset_simulation() -> Dict:
            """重置雷达仿真

            Returns:
                Dict: 重置结果
            """
            try:
                # 如果设置了仿真进程，先停止
                if self.sim_process is not None:
                    self.sim_process.stop()

                # 重置引擎
                self.sim_engine.reset_simulation()

                result = {
                    "message": "Simulation reset successfully",
                    "simulation_time": 0.0,
                    "targets_cleared": True,
                    "detections_cleared": True
                }

                self._log_operation("reset_simulation", {}, result, "SUCCESS")
                return result

            except Exception as e:
                self._log_operation("reset_simulation", {}, str(e), "ERROR")
                raise

        @self.mcp.tool()
        def export_data(filename: Optional[str] = None) -> Dict:
            """导出仿真数据到JSON文件

            Args:
                filename: 文件名(可选), 默认使用时间戳

            Returns:
                Dict: 导出结果信息
            """
            try:
                export_data = self.sim_engine.export_detection_data()
                timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
                if filename is None:
                    filename = f"radar_data_{timestamp}.json"

                os.makedirs("data/export", exist_ok=True)
                filepath = f"data/export/{filename}"

                with open(filepath, 'w', encoding='utf-8') as f:
                    f.write(export_data)

                detection_count = len(self.sim_engine.detection_log)

                result = {
                    "filepath": filepath,
                    "filename": filename,
                    "detection_count": detection_count,
                    "message": f"Data exported successfully to {filepath}"
                }

                self._log_operation("export_data", {"filename": filename}, result, "SUCCESS")
                return result

            except Exception as e:
                self._log_operation("export_data", {"filename": filename}, str(e), "ERROR")
                raise

    # ==================== MCP工具调用接口 ====================

    def call_tool(self, tool_name: str, **kwargs) -> Dict:
        """调用MCP工具（同步包装器）

        Args:
            tool_name: 工具名称
            **kwargs: 工具参数

        Returns:
            Dict: 工具执行结果
        """
        try:
            # 使用asyncio.run运行异步方法
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            try:
                # FastMCP.call_tool返回 (content_list, metadata_dict)
                _, metadata = loop.run_until_complete(self.mcp.call_tool(tool_name, kwargs))
                # 返回metadata中的result
                return metadata.get('result', {})
            finally:
                loop.close()
        except Exception as e:
            return {
                "error": str(e),
                "tool_name": tool_name,
                "arguments": kwargs
            }

    def list_tools(self) -> List[Dict]:
        """列出所有可用的MCP工具（同步包装器）

        Returns:
            List[Dict]: 工具列表
        """
        try:
            # 使用asyncio.run运行异步方法
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            try:
                tools = loop.run_until_complete(self.mcp.list_tools())
                return [
                    {
                        "name": tool.name,
                        "description": tool.description,
                        "inputSchema": tool.inputSchema
                    }
                    for tool in tools
                ]
            finally:
                loop.close()
        except Exception as e:
            print(f"列出工具失败: {e}")
            return []

    # ==================== 兼容旧接口 ====================

    def radar_control(self, command: str) -> str:
        """
        兼容旧的文本命令接口
        将文本命令转换为MCP工具调用
        """
        print(f'\n----Command: {command}')

        try:
            # 将旧命令转换为工具调用
            tool_name, kwargs = self._convert_legacy_command(command)

            # 调用MCP工具
            result = self.call_tool(tool_name, **kwargs)

            # 格式化输出
            return self._format_tool_result(result, tool_name)

        except ValueError as e:
            return f"ERROR: {str(e)}"
        except Exception as e:
            return f"ERROR: Command execution failed: {str(e)}"

    def _convert_legacy_command(self, command: str) -> tuple:
        """将旧命令格式转换为MCP工具调用"""
        # 状态查询
        if self._is_status_query(command):
            return ("get_status", {})

        # 添加目标
        elif command.startswith('添加目标,'):
            parts = command.split(',')
            if len(parts) >= 8:
                return ("add_target", {
                    "target_id": parts[1].strip(),
                    "position": [float(parts[2]), float(parts[3]), float(parts[4])],
                    "velocity": [float(parts[5]), float(parts[6]), float(parts[7])],
                    "rcs": float(parts[8]) if len(parts) > 8 else 1.0
                })

        # 移除目标
        elif command.startswith('移除目标,'):
            target_id = command.split(',', 1)[1].strip()
            return ("remove_target", {"target_id": target_id})

        # 雷达参数
        elif command.startswith('雷达参数,'):
            parts = command.split(',')
            if len(parts) >= 3:
                return ("set_radar_param", {
                    "param_name": parts[1].strip(),
                    "value": float(parts[2].strip())
                })

        # 天气设置
        elif command.startswith('天气设置,'):
            parts = command.split(',')
            if len(parts) >= 5:
                return ("set_weather", {
                    "temperature": float(parts[1]),
                    "humidity": float(parts[2]),
                    "precipitation": float(parts[3]),
                    "wind_speed": float(parts[4])
                })

        # 仿真控制
        elif command in ['开始仿真', 'start', '启动']:
            return ("start_simulation", {})

        elif command in ['停止仿真', 'stop', '停止']:
            return ("stop_simulation", {})

        elif command in ['重置仿真', 'reset', '重置']:
            return ("reset_simulation", {})

        elif command in ['导出数据', 'export', '导出']:
            return ("export_data", {})

        # 未识别命令
        raise ValueError(f"Unknown command: {command}")

    def _is_status_query(self, text: str) -> bool:
        """判断是否为状态查询"""
        text = text.lower()
        query_keywords = {
            '状态', '查询', '查看', '显示', '报告', '情况', '仿真状态',
            'status', 'show', 'display', 'report', 'state'
        }
        return any(keyword in text for keyword in query_keywords)

    def _format_tool_result(self, result: Dict, tool_name: str) -> str:
        """格式化工具执行结果"""
        if 'error' in result:
            return f"ERROR: {result['error']}"

        # 根据不同的工具格式化输出
        if tool_name == "get_status":
            return self._format_status_text(result)
        elif 'message' in result:
            return f"SUCCESS: {result['message']}"
        else:
            return f"SUCCESS: {json.dumps(result, ensure_ascii=False, indent=2)}"

    def _format_status_text(self, status: Dict) -> str:
        """格式化状态文本"""
        targets = status['targets']
        radar = status['radar']
        weather = status['weather']

        return f"""STATUS: 雷达仿真系统状态报告

TIME: 仿真时间: {status['simulation_time']:.2f} 秒
TARGET: 目标总数: {targets['total']}
DETECTED: 已检测目标: {targets['detected']}
RATE: 检测率: {targets['detection_rate']:.2%}
COUNT: 总检测次数: {status['detections']['total_count']}

RADAR: 雷达参数:
- 频率: {radar['frequency_ghz']:.1f} GHz
- 功率: {radar['power_w']:.1f} W
- 天线增益: {radar['antenna_gain_db']:.1f} dB
- 检测范围: {radar['detection_range_km']:.1f} km

WEATHER: 天气条件:
- 温度: {weather['temperature_c']:.1f}°C
- 湿度: {weather['humidity_percent']:.1f}%
- 降水: {weather['precipitation_mmh']:.1f} mm/h
- 风速: {weather['wind_speed_kmh']:.1f} km/h

STATUS: 运行状态: {'运行中' if status['is_running'] else '已停止'}
UPDATE: 更新时间: {status['timestamp']}"""
